﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;

namespace Calendar.Logic.Log
{
    public enum DsLogLevel
    {
        CRITICAL = 1 << 0,
        ERROR = 1 << 1,
        WSERROR = 1 << 2,
        WARNING = 1 << 3,
        SUCCESS = 1 << 4,
        INFO = 1 << 5,
        DEBUG = 1 << 6
    }

    public static class LogManager
    {
        private static readonly Dictionary<DsLogLevel, List<LoggerEventHandler>> Leh;
        private static DsLogLevel _maxLogLevel;

        static LogManager()
        {
            _maxLogLevel = DsLogLevel.INFO;
            Leh = new Dictionary<DsLogLevel, List<LoggerEventHandler>>();
            foreach (var levelName in Enum.GetNames(typeof (DsLogLevel)))
            {
                var level = (DsLogLevel) Enum.Parse(typeof (DsLogLevel), levelName);
                Leh.Add(level, new List<LoggerEventHandler>());
            }

            AddLoggerForAllLevel(new LogFile{LogFolder = @"C:\Calendar\Log\"});
        }

        public static DsLogLevel MaxLogLevel
        {
            set { _maxLogLevel = value; }
        }

        public static string MaxLogLevelName
        {
            get
            {
                return _maxLogLevel.ToString();
            }

            set
            {
                if(Enum.IsDefined(typeof(DsLogLevel), value))
                {
                    _maxLogLevel = (DsLogLevel)Enum.Parse(typeof(DsLogLevel), value);
                }
                else
                {
                    Log(DsLogLevel.WARNING, "Не верное название уровня логирования", "Уровень логирования выставлен по умолчанию");
                }
            }
        }

        public static void AddLogger(DsLogLevel level, LoggerEventHandler handler)
        {
            lock (Leh)
            {
                if (!Leh[level].Contains(handler))
                {
                    Leh[level].Add(handler);
                }
            }
        }

        public static void AddLogger(DsLogLevel[] levels, LoggerEventHandler handler)
        {
            lock (Leh)
            {
                foreach (var level in levels) AddLogger(level, handler); 
            }
        }

        public static void AddLogger(string levels, LoggerEventHandler handler)
        {
            var levelNames = levels.Split(',');
            foreach (var levelName in levelNames)
            {
                if(levelName == "ALL")
                {
                    AddLoggerForAllLevel(handler);
                }
                else if (Enum.IsDefined(typeof(DsLogLevel), levelName))
                {
                    var level = (DsLogLevel)Enum.Parse(typeof(DsLogLevel), levelName);
                    AddLogger(level, handler);
                }   
            }
        }

        public static void AddLoggerForAllLevel(LoggerEventHandler handler)
        {
            foreach (var levelName in Enum.GetNames(typeof(DsLogLevel)))
            {
                var level = (DsLogLevel)Enum.Parse(typeof(DsLogLevel), levelName);

                lock (Leh)
                {
                    if (!Leh[level].Contains(handler))
                    {
                        Leh[level].Add(handler);
                    }
                }
            }
        }

        public static void RemoveAllLogger()
        {
            lock (Leh)
            {
                foreach (var level in Leh)
                {
                    level.Value.Clear();
                }
            }
        }

        public static void RemoveLogger(LoggerEventHandler handler)
        {
            lock (Leh)
            {
                foreach (var level in Leh)
                {
                    if (level.Value.Contains(handler)) level.Value.Remove(handler);
                }
            }
        }

        public static void Log(DsLogLevel level, string title, string msg, params object[] param)
        {
            if (level > _maxLogLevel) return;

            msg = param.Count() > 0 ? string.Format(msg, param) : msg;

            var method = new StackTrace().GetFrame(1).GetMethod();
            var user = HttpContext.Current != null ? (HttpContext.Current.User != null ? (HttpContext.Current.User.Identity.IsAuthenticated ? HttpContext.Current.User.Identity.Name : "NONE") : "NONE") : "NONE";
            title = user + " " + title;

            lock (Leh)
            {
                foreach (var handler in Leh[level])
                {
                    handler.log(level, method.ReflectedType.Name, method.Name, title, msg);
                }
            }
        }

        public static void Log(LoggerMessage msg)
        {
            lock (Leh)
            {
                foreach (var handler in Leh[msg.Level])
                {
                    handler.log(msg.Level, msg.Class, msg.Method, msg.Msg, msg.Comm);
                }
            }
        }

        public static void LoggerError(string msg)
        {
            try
            {
                var st = new StreamWriter("LogManager.log", true);
                st.WriteLine(msg);
                st.Close();
            }
            catch (Exception exc)
            {
                Debug.WriteLine(exc.Message);
            }           
        }

        public static void ShutDown()
        {
            lock (Leh)
            {
                foreach (var level in Leh)
                {
                    foreach (var handler in level.Value)
                    {
                        handler.shutdown();
                    }
                }
            }
        }
    }
}
